#include "tcpmanager.h"

#include <QJsonDocument>
#include <QJsonObject>

#include "usermanager.h"
#include "singleton.h"

TcpManager::TcpManager() 
:_host("")
,_port(0)
,_b_recv_pending(false)
,_message_id(0)
,_message_len(0)
{
    _SetConnect();
    _InitHandlers();
}

void TcpManager::_SetConnect()
{
    // 连接信号和槽函数
    QObject::connect(&_socket, &QTcpSocket::connected, this, [this]() {
        qDebug() << "Connected to server";
        emit sig_tcp_connect(true);
    });
    QObject::connect(&_socket, &QTcpSocket::disconnected, this, [this]() {
        qDebug() << "Disconnected from server";
        emit sig_tcp_connect(false);
    });

    // 链接发送信号
    // 确认所有对 _socket 的操作都通过信号槽机制, 这样可以保证线程安全
    QObject::connect(this, &TcpManager::sig_send_data, this, &TcpManager::slot_send_data);

    // 接收数据信号和槽函数
    QObject::connect(&_socket, &QTcpSocket::readyRead, this, [this]() {
        // 读取所有数据到缓冲区
        _buffer.append(_socket.readAll());

        while (true)
        {
            // 如果还没有解析出头部
            if (!_b_recv_pending)
            {
                if (_buffer.size() < static_cast<int>(sizeof(uint32_t) * 2))
                {
                    return; // 数据不足，继续等待
                }

                // 手动解析消息ID和消息长度（网络字节序要考虑）
                QDataStream headerStream(_buffer.left(sizeof(uint32_t) * 2));
                headerStream.setByteOrder(QDataStream::BigEndian);
                headerStream >> _message_id >> _message_len;

                // 移除已读头部
                _buffer.remove(0, sizeof(uint32_t) * 2);

                qDebug() << "Message ID:" << _message_id << ", Length:" << _message_len;
            }

            // 检查 buffer 是否有完整的消息体
            if (_buffer.size() < _message_len) 
            {
                _b_recv_pending = true; // 数据不足，等待更多
                return;
            }

            _b_recv_pending = false;

            // 取出完整消息体
            QByteArray messageBody = _buffer.left(_message_len);
            _buffer.remove(0, _message_len);

            qDebug() << "Received body msg:" << messageBody;
            // 处理消息
            auto handlerIt = _handlers.find(static_cast<ReqId>(_message_id));
            if (handlerIt == _handlers.end()) 
            {
                qDebug() << "No handler for message ID:" << _message_id;
                emit sig_login_failed(ErrorCode::ERR_CALL_BCLK_fAILED);
                continue; // 无处理函数，继续处理下一个消息
            }
            handlerIt.value()(static_cast<ReqId>(_message_id), _message_len, messageBody);
        }
    });

    // 错误信号和槽函数
    QObject::connect(&_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred), [&](QAbstractSocket::SocketError socketError) {
        Q_UNUSED(socketError) // 抑制“未使用参数”的编译器警告。
        qDebug() << "Error:" << _socket.errorString();
    });
}

void TcpManager::_InitHandlers()
{
    // 登录回调处理
    this->_handlers.insert(ReqId::ID_CHAT_LOGIN, [this](ReqId id, int32_t len, const QByteArray& data){
        qDebug() << "id:" << id << " len:" << len << " data:" << data;
        QJsonDocument doc = QJsonDocument::fromJson(data);
        if (doc.isNull()) 
        {
            qDebug() << "JSON解析失败";
            emit sig_login_failed(ErrorCode::ERR_JSON);
            return;
        }

        QJsonObject obj = doc.object();
        if(!obj.contains("code"))
        {
            qDebug() << "JSON对象不包含'code'";
            emit sig_login_failed(ErrorCode::ERR_JSON);
            return;
        }
        int code = obj["code"].toInt();
        if(code != ErrorCode::SUCCESS)
        {
            qDebug() << "登录失败，错误码:" << code;
            emit sig_login_failed(code);
        }

        MagicSingleton<UserManager>::GetInstance()->setName(obj["name"].toString());
        MagicSingleton<UserManager>::GetInstance()->setToken(obj["token"].toString());
        MagicSingleton<UserManager>::GetInstance()->setUid(obj["id"].toInt());

        qDebug() << "name: " << obj["name"].toString() << " token: " << obj["token"].toString() << " id: " << obj["id"].toInt();
        emit sig_switch_chatdlg();
    });
}


void TcpManager::slot_tcp_connect(ServerInfo info)
{
    _host = info.Host;
    _port = static_cast<quint16>(info.Port.toUInt());
    _socket.connectToHost(_host, _port);
    qDebug() << "Connecting to" << _host << ":" << _port;
}


void TcpManager::slot_send_data(ReqId reqId, QString data)
{
    if (!_socket.isOpen())
    {
        qDebug() << "Socket is not open. Cannot send data.";
        return;
    }

    QByteArray byteArray = data.toUtf8();

    uint32_t id = static_cast<uint32_t>(reqId);
    uint32_t len = static_cast<uint32_t>(byteArray.size());

    QByteArray sendData;
    QDataStream out(&sendData, QIODevice::WriteOnly);
    out.setByteOrder(QDataStream::BigEndian);
    out << id << len;

    sendData.append(byteArray);

    _socket.write(sendData);
}
